package com.own.business.wallet.controller.user;

import com.own.business.wallet.business.service.WalletHistoryService;
import com.own.business.wallet.business.service.WalletService;
import com.own.business.wallet.business.util.WalletBusinessUtil;
import com.own.business.wallet.common.em.WalletExceptionEnum;
import com.own.business.wallet.common.exception.WalletException;
import com.own.business.wallet.controller.user.form.WalletGetPayTokenForm;
import com.own.business.wallet.controller.user.form.WalletPayForm;
import com.own.business.wallet.entity.query.WalletHistoryQuery;
import com.own.business.wallet.entity.vo.WalletHistoryVo;
import com.own.component.common.base.controller.BaseController;
import com.own.component.common.exception.BusinessSimpleException;
import com.own.component.common.login.util.SessionUserUtil;
import com.own.component.common.model.PageModel;
import com.own.component.common.model.R;
import com.own.component.common.model.ResultModel;
import com.own.component.common.util.encrypt.EncryptUtil;
import com.own.component.common.util.encrypt.model.CustomEncryptKey;
import com.own.component.log.operation.aop.LogOperationAop;
import com.own.component.log.operation.aop.LogOperationModuleAop;
import com.own.component.sensitive.check.SensitiveTokenUtil;
import com.own.component.store.core.Store;
import com.own.component.store.core.util.base.RsaKeyUtil;
import com.own.constant.ConstantApiPrefix;
import com.own.constant.ConstantBeanSuffix;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.UUID;

/**
 * UserWalletHistoryController
 *
 * @author chenxueli
 * @date 2023-07-13 16:07:39
 */
@Tag(name = "钱包订单流水" + ConstantBeanSuffix.USER_CLIENT + ConstantBeanSuffix.CONTROLLER)
@LogOperationModuleAop("钱包订单流水")
@RestController
@RequestMapping(ConstantApiPrefix.BASE_API_V1_PREFIX + "business/wallet/history")
public class UserWalletHistoryController extends BaseController {

    @Resource
    private WalletService walletService;
    @Resource
    private WalletHistoryService walletHistoryService;
    @Resource
    private WalletBusinessUtil walletBusinessUtil;
    @Resource
    private SensitiveTokenUtil sensitiveTokenUtil;

    @Resource
    private Store<String> store;

    @Resource
    private RsaKeyUtil rsaKeyUtil;

    @Deprecated
    @LogOperationAop
    @Operation(summary = "订单支付")
    @PostMapping("/pay/{tradeNo}")
    public ResultModel<Boolean> pay(
            @Parameter(description = "订单号", required = true) @PathVariable String tradeNo
    ) {
        walletBusinessUtil.pay(tradeNo);
        return R.success(true);
//        throw new BusinessSimpleException("该接口已经被弃用，请使用新的订单支付接口");
    }

    @LogOperationAop
    @Operation(summary = "支付密码验证（获取支付令牌）")
    @PostMapping("/token/pay")
    public ResultModel<String> getPayToken(
            @RequestBody WalletGetPayTokenForm form
    ) {
        form.check();
        var loginUser = SessionUserUtil.getLoginUser();
        // 获取真实的密码
        var password = rsaKeyUtil.decrypt(form.getKey(), form.getPassword());
        // 验证密码是否正确
        var flag = walletService.checkPassword(loginUser.userId(), password);
        if (!flag) {
            throw new BusinessSimpleException(WalletExceptionEnum.PASSWORD_ERROR);
        }
        // 生成一次性token
        var token = UUID.randomUUID().toString().replaceAll("-", "");
        // 生成token并保存到redis中
        store.value().set("pay:token:" + loginUser.userId(), token, Duration.ofMinutes(15));
        if (StringUtils.isNotBlank(form.getPublicKey())) {
            token = EncryptUtil.RSA.encrypt(token, CustomEncryptKey.builder().publicKey(form.getPublicKey()).build());
        }
        return R.success(token);
    }

    @LogOperationAop
    @Operation(summary = "订单支付")
    @PostMapping("/pay")
    public ResultModel<Boolean> pay(
            @RequestBody WalletPayForm form
    ) {
        form.check();
        var loginUser = SessionUserUtil.getLoginUser();
        if (StringUtils.isNotBlank(form.getPassword())) {
            // 获取真实的密码
            var password = rsaKeyUtil.decrypt(form.getKey(), form.getPassword());
            // 验证密码是否正确
            var flag = walletService.checkPassword(loginUser.userId(), password);
            if (!flag) {
                throw new BusinessSimpleException(WalletExceptionEnum.PASSWORD_ERROR);
            }
        }
        if (StringUtils.isNotBlank(form.getPayToken())) {
            // 获取真实的token
            var token = rsaKeyUtil.decrypt(form.getKey(), form.getPayToken());
            var cacheToken = store.value().get("pay:token:" + loginUser.userId());
            if (!token.equals(cacheToken)) {
                throw new BusinessSimpleException(WalletExceptionEnum.PASSWORD_ERROR);
            }
        }
        walletBusinessUtil.pay(form.getTradeNo());
        return R.success(true);
    }

    @LogOperationAop
    @Operation(summary = "根据外部订单号获取内部订单号")
    @PostMapping("/exchange/{tradeNo}")
    public ResultModel<String> exchange(
            @Parameter(description = "订单号", required = true) @PathVariable String tradeNo
    ) {
        var po = walletHistoryService.getByOutTradeNo(tradeNo);
        if (po == null) {
            throw new WalletException("订单不存在");
        }
        return R.success(po.getTradeNo());
    }

    @LogOperationAop
    @Operation(summary = "查询订单流水记录")
    @PostMapping("/page")
    public ResultModel<PageModel<WalletHistoryVo>> page(
            @RequestBody WalletHistoryQuery query
    ) {
        var loginUser = SessionUserUtil.getLoginUser();
        query.setUserId(loginUser.userId());
        var pageModel = walletHistoryService.page(query);
        return R.success(pageModel);
    }

    @LogOperationAop
    @Operation(summary = "根据订单号查询订单的详情")
    @GetMapping("/{tradeNo}")
    public ResultModel<WalletHistoryVo> getByTradeNo(
            @Parameter(description = "订单号", required = true) @PathVariable String tradeNo
    ) {
        var po = walletHistoryService.getByTradeNo(tradeNo);
        if (po == null) {
            throw new RuntimeException("订单不存在");
        }
        return R.success(new WalletHistoryVo(po));
    }

}
